package cryptotest

import spinal.core._
import spinal.core.sim._
import org.scalatest.FunSuite
import spinal.crypto.BigIntToHexString
import spinal.crypto.primitive.keccak.KeccakF_Std



class SpinalSimKeccakFStdTester extends FunSuite {

  test("KeccakF_1600"){

    SimConfig.withWave(3).withConfig(SpinalConfig(inlineRom = true)).compile(new KeccakF_Std(1600)).doSim{ dut =>

      dut.clockDomain.forkStimulus(2)

      // pattern
      val pIn = List(
        BigInt("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 16),
        BigInt("2D5C954DF96ECB3C6A332CD07057B56D093D8D1270D76B6C8A20D9B25569D0944F9C4F99E5E7F156F957B9A2DA65FB3885773DAE1275AF0DFAF4F247C3D810F71F1B9EE6F79A8759E4FECC0FEE98B42568CE61B6B9CE68A1DEEA66C4BA8F974F33C43D836EAFB1F5E00654042719DBD97CF8A9F009831265FD5449A6BF17474397DDAD33D8994B4048EAD5FC5D0BE774E3B8C8EE55B7B03C91A0226E649E42E9900E3129E7BADD7B202A9EC5FAA3CCE85B3402464E1C3DB6609F4E62A44C105920D06CD26A8FBF5C", 16),
        BigInt("3A7C2A5F40A6EB2E6D65A12941DC4578421FDC535744C454D7D362577104BE802760D9DB642351F4EE3E72527BEE47BDCD3828BB52A2C82C77C6E8A0A1F7DD0DB20410D9920D330609FAF1CBD8AAEE346908B5414252574F4DC4B495E348785257C8B308E597ABC8CFD1CA17D26E64FFE0952BC6B5ECC88841C66D9E7A092BA08E0C70F08AF986235F07630B6DF1ADA7F312E32DDF61343B5D1093D26FCE27EEDB0F640215B2AAE0400EEA2CC76F8716CF6DE6E9838329953BA0E9CD540AEEC472011C1D6BF77DAC", 16),
        BigInt("971CECC10266B10E6ADAE29CE71EAE385B331D9109F32D8947F889804480CDCEFECD01EAF3FD184BFF02D96272A0F9FA7305A59462631C8CADE70BA47BBB82B2DDBB6C2E22C7C2A916C92997F043DCD4287E1DC935D7A9972800BC77799B1CE47CCC56C5A551A5B55F7EBC347B2216D974C621FCD15148895D2B628A78B8B87DC52FF58E3A695D87A811456522C06885AEB698C6CE808B73962FFCD5A04C204F24297C7912E1BD9F02BCFEDFF5953DF1FE0A74D3A3676EC6A2F3B516FD29D10E80FC705B68E01610", 16),
        BigInt("E409BECC15D4110ABE07B597F646971BA20860D19A3176333D00CCDE8328DE56ED02F1DFA7ECF90B33EB764F744CC239C9FB8C0916C5443DBAAFC63179C24F4FD1B8CD19229301D0C025BFF35A6DE35BC324DCF0129AE69C7948559948D8E9251D3E08195A76A2BFC55247327076D2F7A3E4F405E6235A3B6A985AA8BC1CB5C55B719D0BF123A1E491FB8DB83291DF4C5296F8B6F90985006428D0CBC5A701F0258EE8110E5F6AAC687E1B35262CAD37DE2D00C16CFE6760D61A2EB46F9050CB7FE279B794440AB5", 16)
      )


      val pOut = List(
        BigInt("F1258F7940E1DDE784D5CCF933C0478AD598261EA65AA9EEBD1547306F80494D8B284E056253D057FF97A42D7F8E6FD490FEE5A0A44647C48C5BDA0CD6192E76AD30A6F71B19059C30935AB7D08FFC64EB5AA93F2317D635A9A6E6260D71210381A57C16DBCF555F43B831CD0347C82601F22F1A11A5569F05E5635A21D9AE6164BEFEF28CC970F2613670957BC46611B87C5A554FD00ECB8C3EE88A1CCF32C8940C7922AE3A26141841F924A2C509E416F53526E70465C275F644E97F30A13BEAF1FF7B5CECA249", 16),
        BigInt("55EABB80767D364686C354C8D01CBACE9452D254B0979B3DDE59422BE2C66F16C660E4F2D4D8212E78414F691B639BB3CBB20F9F1B22E381CF16DA5FAC2DA63F83C0B76552D95F7C44EFC84EAF017E1548D380FF3E532C9592436EC5C5E02F05BDE57CA1EE8DE7E9240970468A1FD1B012A978439CBB7686D26B59FCCEFF8B4DD2AA0F472110FFF87BD44ABF53F72551E15AD2B722D00BB7C56095932C792C459E02D1766AD3A79C312F2DA72ADA4EC368B9F274A8D7D6B92B7239F7E51EEA1EB6947F6894D77AEB", 16),
        BigInt("C9F309FF271C66319281C8B3825841B42219CB1928CA14C4F50D1D2AE140281AF0A33A68985B6934D8A79767500429F6BE55A8FFF0767FAFBC2A9530CCA9D7A87E7947DEBC81B851772429B40AA052A858F891E79CE863653110152CADF8860F7F6F0628BDA22D08A89FB4DB4293CC0A390BCA6688AB09BEFADCBB8BBBEDCE4B2D78A388460C4A73E692F192C06EA9AE909DE0D99F0083F076773FCDC7E9D261344D00AE9D02C8539D85CB92EF2A61550A1A8ECF6537E0B3A6DA3FB1F1688E95CFE9307B7DB8BED0", 16),
        BigInt("96FD5DCE98F24747BC17F718A5EE2C326C35A669C2803013B609BCA1CB4290D79ACB9589DFE9E24D23CD87D2100A09C81D045BFEC0E027B456C35E5CA9BBA89FFE57C5CEA57A60C2E7EE16B2641E669B68985ABFA550BB66F6923F628221835B6FFA61F3003DA12AEC8239484A92E877C0B246BCCD3FC38578C896C5470D48A7861A0C89AD6C9AC44721476CB83EA905C0B5307B7F640E2C1F273DC75696478A22D54D8F7705A150BD92ECCC819E4ABE58137F2452C9686A0F61A7F4CA21445709683D0401018460", 16),
        BigInt("D1AED9E3149CF176FA5784FB1CD05D62410AD4C334AC5843FD5D711A3619C022EF3C5A52A19521C388CA427AD4093D4030CAE0756CCB675DF1BC6D1003600450551E54846019C2740F0E2C4EED72C02E7FA05C108E09CA188A77C0D124F5E5B35BFCB30FC8DE496DEADC837994534B200B81F95E44D6BB58DAD404401A489506D60AB885FE20EBF52EB0F3A94432ABCF0186261253FAA874691B683FD0CEB84A26DE0E2E35F2AD7A5F559030137AD5FEB372861AA4A3C6AF1AA9D09D3BA9A957FA7EAA90728CA360", 16)
      )

      // initialize value
      dut.io.cmd.valid  #= false
      dut.io.cmd.payload.randomize()

      for((dIn, dOut) <- pIn.zip(pOut)){

        dut.clockDomain.waitActiveEdge()

        dut.io.cmd.valid   #= true
        dut.io.cmd.payload #= dIn

        dut.clockDomain.waitActiveEdgeWhere(dut.io.rsp.valid.toBoolean)
        dut.io.cmd.valid #= false

        val rtlState_out = BigInt(dut.io.rsp.payload.toBigInt.toByteArray.takeRight(dut.io.rsp.payload.getWidth / 8))
        val refState_out = BigInt(dOut.toByteArray.takeRight(dut.io.rsp.payload.getWidth / 8))

        assert(rtlState_out == refState_out , s"Wrong result RTL ${BigIntToHexString(rtlState_out)} !=  REF ${BigIntToHexString(refState_out)}")

        dut.clockDomain.waitActiveEdge(5)

      }
    }
  }
}
